package risoe.syslab.fhnew.controller;

/*
 * Copyright (c) 2012-2014, Technical University of Denmark (DTU)
 * All rights reserved.
 * 
 * The Flexhouse 2.0 platform ("this software") is licensed under the
 * BSD 3-clause license.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *   - Neither the name of DTU nor the names of its contributors may be used to
 *     endorse or promote products derived from this software without specific
 *     prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE TECHNICAL UNIVERSITY OF DENMARK BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

import java.io.File;
import java.util.HashMap;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import risoe.syslab.fhnew.common.SystemConstants.DeviceType;
import risoe.syslab.fhnew.config.ActuatorConfig;
import risoe.syslab.fhnew.config.BuildingConfig;
import risoe.syslab.fhnew.gui.DocumentPreparedListener;
import risoe.syslab.fhnew.gui.VisualizationEvent;
import risoe.syslab.fhnew.gui.VisualizationEvent.EventType;
import risoe.syslab.fhnew.gui.VisualizationEventListener;
import risoe.syslab.fhnew.gui.VisualizationHolder;
import risoe.syslab.fhnew.gui.VisualizationUpdate;
import risoe.syslab.fhnew.hw.Sensor;
import risoe.syslab.model.CompositeMeasurement;

public class DefaultSwitchController extends DefaultController{

	@SuppressWarnings("unused")
  private SwitchVisualizationHandler mVisualizationHandler;
	private double mState = 1.0;

	public DefaultSwitchController(ControllerManager manager,
			BuildingConfig building) {
		super(manager, building);
		
		// Turn all relays on
		for (ActuatorConfig config : building.getAllActuators()){
			if (config.getType() == DeviceType.Switch){
				// turn on
				setActuator(config.getName(), new CompositeMeasurement(mState));
			}
		}
	}

	@Override
	public void sensorUpdated(Sensor sensor) {
		// Ignore
	}
	
	@Override
	public VisualizationHolder getVisualization() {
		// Start visualization
		VisualizationHolder holder = new VisualizationHolder(DefaultSwitchController.class.getSimpleName(), new File(SwitchVisualizationHandler.PATH).toURI());
		mVisualizationHandler = new SwitchVisualizationHandler(holder);
		return holder;
	}

	@Override
	public void kill() {
		// No cleanup neccesary
	}
	
	/**
	 * Class responsible for handling the visualization associated with the default switch controller
	 * @author M. Svendsen
	 */
	private class SwitchVisualizationHandler implements DocumentPreparedListener, VisualizationEventListener{
		// Constants
		public static final String PATH = "media/DefaultSwitchVis.svg";
		public static final String STATES_ID = "text3183-4-8";
		public static final String BUTTON_ON_ID = "rect3014";
		public static final String BUTTON_OFF_ID = "rect3016";

		private HashMap<String, String> mSwitchMap = new HashMap<String, String>();
		private Document mDocument;
		private boolean mInitialized = false;
		private VisualizationHolder mVisualizationHolder;

		public SwitchVisualizationHandler(VisualizationHolder holder) {
			mVisualizationHolder = holder;

			mVisualizationHolder.setOnDocumentPreparedListener(this);
			mVisualizationHolder.setOnVisualizationEventListener(this);
			mVisualizationHolder.listenTo(BUTTON_ON_ID);
			mVisualizationHolder.listenTo(BUTTON_OFF_ID);
		}

		@Override
		public void onVisualizationEvent(VisualizationEvent event) {	
			if (!mInitialized) return;
			
			if (event.getEventType() == EventType.Mouse_Click){
				if (event.getID().equalsIgnoreCase(BUTTON_ON_ID)) {
					toggleSwitches(1.0);
				}
				else if (event.getID().equalsIgnoreCase(BUTTON_OFF_ID)) {
					toggleSwitches(0.0);
				}
			}
		}

		@Override
		public void onDocumentReady(Document document) {
			mDocument = document;

			// Create a map that links room names to SVG ids
			VisualizationUpdate update = getUpdate();
			NodeList nodes = mDocument.getElementById(STATES_ID).getChildNodes();
			int i = 0;
			
			for (ActuatorConfig actuator : mBuildingConfig.getAllActuators()){
				if (actuator.getType() == DeviceType.Switch){
					String id = nodes.item(i++).getAttributes().getNamedItem("id").getTextContent();

					// Save the reference
					mSwitchMap.put(actuator.getName(), id);

					// Add command
					update.addCommand(id, actuator.getName()+": "+mState);
				}
			}

			mControllerManager.executeVisualizationUpdateInternal(update);
			mInitialized = true;
		}
		
		public void toggleSwitches(double newState){
			if (newState == mState) return;
	
			// Change state
			if (mState == 1.0){
				mState = 0.0;
			}
			else{
				mState = 1.0;
			}
			
			// Request actuation
			for (String actuatorName : mSwitchMap.keySet()){
				VisualizationUpdate update = getUpdate();
				setActuator(actuatorName, new CompositeMeasurement(mState));
				update.addCommand(mSwitchMap.get(actuatorName), actuatorName+": "+mState);
				
				// Update UI
				mControllerManager.executeVisualizationUpdateInternal(update);
			}
		}

		/**
		 * Convenience method to obtain a VisualizationUpdate
		 */
		private VisualizationUpdate getUpdate(){
			return new VisualizationUpdate(DefaultSwitchController.class.getSimpleName());
		}
	}
}
